/*
 * CommunicationRobot5.cpp
 *
 *  
 */

#include "CommunicationRobot5.h"
#include "../capa_servicios_distribuidos/QueueLauncher.h"
#include "../channel_common/agent_address_service/AgentAddressService.h"
#include "../distributed_semaphore/comun/DSEMCommon.h"

namespace middleware {

const Uid CommunicationRobot5::UIDCanastos 			 = "robot5Canastos";
const Uid CommunicationRobot5::UIDCintas             = "robot5Cintas";
const Uid CommunicationRobot5::UIDProduccion         = "robot5Produccion";
const Uid CommunicationRobot5::UIDGabinetes          = "robot5Gabinetes";
const Uid CommunicationRobot5::UIDIntercambio        = "robot5Intercambio";
const Uid CommunicationRobot5::UIDRecepcionCanastos = "robot5RecepcionCanastos";
const Uid CommunicationRobot5::UIDEnviosADP 		 = "robot5EnviosADP";

const std::string CommunicationRobot5::R5_SEM_PATH = "/tmp/robot5sem";
const std::string CommunicationRobot5::R5_SHMEM_PATH = "/tmp/robot5shmem";

const int CommunicationRobot5::mtpyeRobot5RecepcionCanastos = R5_TIPO_RECEPCION_CANASTO;

CommunicationRobot5::CommunicationRobot5(std::string hostName,R5CommunicationType type) :
							colaCanastos(ipc::MessageQueue<PedidoCanasto>::get(IPCUids::getFile(UIDCanastos)+hostName,IPCUids::getKey(UIDCanastos))),
							colaCintas(ipc::MessageQueue<PedidoCintas>::get(IPCUids::getFile(UIDCintas)+hostName,IPCUids::getKey(UIDCintas))),
							colaProduccion(ipc::MessageQueue<PedidoProduccion>::get(IPCUids::getFile(UIDProduccion)+hostName,IPCUids::getKey(UIDProduccion))),
							//colaGabinetes(ipc::MessageQueue<PedidoGabinetes>::get(IPCUids::getFile(UIDGabinetes)+hostName,IPCUids::getKey(UIDGabinetes))),
							colaIntercambio(ipc::MessageQueue<Canasto>::get( IPCUids::getFile(UIDIntercambio)+hostName,IPCUids::getKey(UIDIntercambio))),
							colaRecpcionCanastos(ipc::MessageQueue<Canasto>::get(IPCUids::getFile(UIDRecepcionCanastos)+hostName,IPCUids::getKey(UIDRecepcionCanastos))),
							shMemPendientes(ipc::SharedMemoryInterface<PendientesRobot5>::get(R5_SHMEM_PATH, R5_SHMEM_PENDIENTES_KEY, DSM_ENABLED ? DSMID_PENDROBOT5 : 0)),
							shMemEstado(ipc::SharedMemoryInterface<EstadoRobot5>::get(R5_SHMEM_PATH, R5_SHMEM_ESTADO_KEY, DSM_ENABLED ? DSMID_EROBOT5 : 0))
{

	/* Get semaphores by type, just those needed*/
	if (DSEM_ENABLED) {
		switch (type) {
			case R5:
				this->semBloqueo = ipc::Semaphore::get(getSemRobot5FileWait(), getSemControlRobot5Key());
				break;
			case ADP:
			case AGV:
			case ROBOT11:
				this->semBloqueo = ipc::Semaphore::get(getSemRobot5FileSignal(), getSemControlRobot5Key());
				break;
		}
	} else {
		this->semBloqueo = ipc::Semaphore::get(R5_SEM_PATH, R5_SEM_KEY);
	}

	mtpyeRobot5Canastos = channel::AgentAddressService::resolve(UIDCanastos);
	mtpyeRobot5Cintas = channel::AgentAddressService::resolve(UIDCintas);
	mtpyeRobot5Produccion = channel::AgentAddressService::resolve(UIDProduccion);
//	mtpyeRobot5Gabinetes = channel::AgentAddressService::resolve(UIDGabinetes);
	mtpyeRobot5EnviosADP = channel::AgentAddressService::resolve(UIDEnviosADP);

	mtypeRobot5IntercambioAGVIzq = channel::AgentAddressService::resolve(UIDIntercambio + "agvIzq");
	mtypeRobot5IntercambioAGVMed = channel::AgentAddressService::resolve(UIDIntercambio + "agvMed");
	mtypeRobot5IntercambioAGVDer = channel::AgentAddressService::resolve(UIDIntercambio + "agvDer");
}

void CommunicationRobot5::pedirCanastoAR5(PedidoCanasto pedido){
	colaCanastos.put(mtpyeRobot5Canastos, pedido);
}

PendientesRobot5 CommunicationRobot5::getListaPedidos(){
	shMemPendientes.lock();
	PendientesRobot5 pendientes = shMemPendientes.read(0);
	return pendientes;
}

void CommunicationRobot5::setListaPedidos(PendientesRobot5 pendientes){
	shMemPendientes.write(pendientes);
	shMemPendientes.unlock();
}

EstadoRobot5 CommunicationRobot5::verEstado(){
	shMemEstado.lock();
	return shMemEstado.read();
}

void CommunicationRobot5::liberarPendientes(){
	shMemPendientes.unlock();
	return;
}

void CommunicationRobot5::despertar(){
	shMemEstado.write(R5_ESTADO_ACTIVO);
	semBloqueo.signal();
}

void CommunicationRobot5::dormir(){
	semBloqueo.wait();
}

void CommunicationRobot5::despertarInteligente(){
	shMemEstado.lock();
	EstadoRobot5 estado = shMemEstado.read();
	if (estado == R5_ESTADO_DURMIENDO) {
		estado = R5_ESTADO_ACTIVO;
		shMemEstado.write(estado);
		semBloqueo.signal();
	}
	shMemEstado.unlock();
}

void CommunicationRobot5::incrementarPedidos(int index){
	PendientesRobot5 pendientes = this->getListaPedidos();
	pendientes.contador[index]++;
	this->setListaPedidos(pendientes);
}

void CommunicationRobot5::decrementarPedidos(int index){
	PendientesRobot5 pendientes = this->getListaPedidos();
	pendientes.contador[index]--;
	this->setListaPedidos(pendientes);
}

void CommunicationRobot5::enviarAvisoDeCintaAR5(PedidoCintas pedido){
	colaCintas.put(mtpyeRobot5Cintas, pedido);
}

Canasto CommunicationRobot5::getCanastoDeADP(){
	return colaRecpcionCanastos.get(mtpyeRobot5RecepcionCanastos);
}

void CommunicationRobot5::pedirCanastoAlADP(Canasto c){
	//FIXME Mock
	colaRecpcionCanastos.put(mtpyeRobot5RecepcionCanastos, c);
}

void CommunicationRobot5::llevarCanastoAlAGV(int idAGV,Canasto canasto){
	//segun el id del agv se manda con ese id por la cola
	int mtype;
	if (idAGV == (int) ('i')) {
		mtype = mtypeRobot5IntercambioAGVIzq;
	} else if (idAGV == (int) ('m')) {
		mtype = mtypeRobot5IntercambioAGVMed;
	} else if (idAGV == (int) ('d')) {
		mtype = mtypeRobot5IntercambioAGVDer;
	}

	colaIntercambio.put(mtype, canasto);
}

Canasto CommunicationRobot5::recibirCanastoDel5(int idAGV) {
	int mtype;
	if (idAGV == (int) ('i')) {
		mtype = mtypeRobot5IntercambioAGVIzq;
	} else if (idAGV == (int) ('m')) {
		mtype = mtypeRobot5IntercambioAGVMed;
	} else if (idAGV == (int) ('d')) {
		mtype = mtypeRobot5IntercambioAGVDer;
	}

	return colaIntercambio.get(mtype);
}

PedidoCanasto CommunicationRobot5::getPedidoDeCanasto() {
	return colaCanastos.get(mtpyeRobot5Canastos);
}

PedidoCintas CommunicationRobot5::getPedidoDeCinta() {
	return colaCintas.get(mtpyeRobot5Cintas);
}

PedidoProduccion CommunicationRobot5::getPedidoDeProd() {
	return colaProduccion.get(mtpyeRobot5Produccion);
}

void CommunicationRobot5::noHacerNada() {
	shMemEstado.lock();
	shMemEstado.write(R5_ESTADO_DURMIENDO);
	shMemEstado.unlock();
	shMemPendientes.unlock();
	semBloqueo.wait();
}

void CommunicationRobot5::create(R5CommunicationType type,
		std::string hostName) {
	int mtypeRobot5IntercambioAGVIzq = 0;
	int mtypeRobot5IntercambioAGVMed = 0;
	int mtypeRobot5IntercambioAGVDer = 0;
	int mtpyeRobot5Canastos = 0;
	int mtpyeRobot5Cintas = 0;
	int mtpyeRobot5Produccion = 0;
	int mtpyeRobot5EnviosADP = 0;
	// solo registrar para el receptor
	if (type == R5) {
		mtpyeRobot5Canastos = channel::AgentAddressService::registerName(
				UIDCanastos);
		mtpyeRobot5Cintas = channel::AgentAddressService::registerName(
				UIDCintas);
		mtpyeRobot5Produccion = channel::AgentAddressService::registerName(
				UIDProduccion);
		mtpyeRobot5EnviosADP = channel::AgentAddressService::registerName(
				UIDEnviosADP);
	} else if (type == AGV) {
		mtypeRobot5IntercambioAGVIzq =
				channel::AgentAddressService::registerName(
						UIDIntercambio + "agvIzq");
		mtypeRobot5IntercambioAGVMed =
				channel::AgentAddressService::registerName(
						UIDIntercambio + "agvMed");
		mtypeRobot5IntercambioAGVDer =
				channel::AgentAddressService::registerName(
						UIDIntercambio + "agvDer");
	}

	/* Esta cola la usa el 5 localmente siempre */
	ipc::MessageQueue < Canasto
			> ::createNonExclusive(
					IPCUids::getFile(UIDRecepcionCanastos) + hostName,
					IPCUids::getKey(UIDRecepcionCanastos));
	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
			< PedidoCanasto
			> (UIDCanastos, hostName,
					(type == R5) ?
							servicios_distribuidos::QUEUE_RECV :
							servicios_distribuidos::QUEUE_SEND, mtpyeRobot5Canastos);
	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
			< PedidoCintas
			> (UIDCintas, hostName,
					(type == R5) ?
							servicios_distribuidos::QUEUE_RECV :
							servicios_distribuidos::QUEUE_SEND, mtpyeRobot5Cintas);
	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
			< PedidoProduccion
			> (UIDProduccion, hostName,
					(type == R5) ?
							servicios_distribuidos::QUEUE_RECV :
							servicios_distribuidos::QUEUE_SEND, mtpyeRobot5Produccion);

	/* Colas de intercambio con los distintos AGV */

		servicios_distribuidos::QueueLauncher::createDistributedQueueByUid < Canasto
				> (UIDIntercambio, hostName,
						(type == AGV) ?
								servicios_distribuidos::QUEUE_RECV :
								servicios_distribuidos::QUEUE_SEND, mtypeRobot5IntercambioAGVIzq);
		servicios_distribuidos::QueueLauncher::createDistributedQueueByUid < Canasto
				> (UIDIntercambio, hostName,
						(type == AGV) ?
								servicios_distribuidos::QUEUE_RECV:
								servicios_distribuidos::QUEUE_SEND, mtypeRobot5IntercambioAGVMed);
		servicios_distribuidos::QueueLauncher::createDistributedQueueByUid < Canasto
				> (UIDIntercambio, hostName,
						(type == AGV) ?
								servicios_distribuidos::QUEUE_RECV :
								servicios_distribuidos::QUEUE_SEND, mtypeRobot5IntercambioAGVDer);

	/* Get semaphores by type, just those needed*/
	if (DSEM_ENABLED) {
		switch (type) {
			case R5:
				ipc::Semaphore::createNonExclusive(getSemRobot5FileWait(), getSemControlRobot5Key());
				break;
			default:
			case ADP:
			case AGV:
			case ROBOT11:
				ipc::Semaphore::createNonExclusive(getSemRobot5FileSignal(), getSemControlRobot5Key());
				break;
		}
	} else {
		ipc::Semaphore::createNonExclusive(R5_SEM_PATH, R5_SEM_KEY);
	}

	/* Create SHMems */
	if (type == R5) {
		ipc::SharedMemoryInterface<EstadoRobot5>::create(R5_SHMEM_PATH, R5_SHMEM_ESTADO_KEY);
		ipc::SharedMemoryInterface<PendientesRobot5>::create(R5_SHMEM_PATH, R5_SHMEM_PENDIENTES_KEY);
	}
}

void CommunicationRobot5::destroy(R5CommunicationType type, std::string hostName) {
	ipc::MessageQueue < PedidoCanasto
			> ::destroyNonExclusive(IPCUids::getFile(UIDCanastos) + hostName,
					IPCUids::getKey(UIDCanastos));
	ipc::MessageQueue < PedidoCintas
			> ::destroyNonExclusive(IPCUids::getFile(UIDCintas) + hostName,
					IPCUids::getKey(UIDCintas));
	ipc::MessageQueue < PedidoProduccion
			> ::destroyNonExclusive(IPCUids::getFile(UIDProduccion) + hostName,
					IPCUids::getKey(UIDProduccion));
	//	ipc::MessageQueue<PedidoGabinetes>::destroy( IPCUids::getFile(UIDGabinetes)+hostName,IPCUids::getKey(UIDGabinetes));
	ipc::MessageQueue < Canasto
			> ::destroyNonExclusive(IPCUids::getFile(UIDIntercambio) + hostName,
					IPCUids::getKey(UIDIntercambio));
	ipc::MessageQueue < Canasto
			> ::destroyNonExclusive(
					IPCUids::getFile(UIDRecepcionCanastos) + hostName,
					IPCUids::getKey(UIDRecepcionCanastos));
	ipc::MessageQueue < PedidoCanasto
			> ::destroyNonExclusive(IPCUids::getFile(UIDEnviosADP) + hostName,
					IPCUids::getKey(UIDEnviosADP));

	if (type == R5) {
		ipc::SharedMemoryInterface < PendientesRobot5
				> ::destroy(R5_SHMEM_PATH, R5_SHMEM_PENDIENTES_KEY);
		ipc::SharedMemoryInterface < EstadoRobot5
				> ::destroy(R5_SHMEM_PATH, R5_SHMEM_ESTADO_KEY);
	}

	ipc::Semaphore::destroyNonExclusive(getSemRobot5FileWait(), getSemControlRobot5Key());
	ipc::Semaphore::destroyNonExclusive(getSemRobot5FileSignal(), getSemControlRobot5Key());
	ipc::Semaphore::destroyNonExclusive(R5_SEM_PATH, R5_SEM_KEY);
}

void CommunicationRobot5::enviarAProducir(PedidoProduccion pedido) {
	this->colaProduccion.put(mtpyeRobot5Produccion, pedido);
}

CommunicationRobot5::~CommunicationRobot5() {
}

std::string CommunicationRobot5::getSemRobot5FileWait() {
	return R5_SEM_PATH + "wait";
}

std::string CommunicationRobot5::getSemRobot5FileSignal() {
	return R5_SEM_PATH + "signal";
}

std::string CommunicationRobot5::getSemControlName() {
	return "robot5Control";
}

char CommunicationRobot5::getSemControlRobot5Key() {
	return R5_SEM_KEY;
}
/* namespace middleware */

}

